home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 22 code / PCI Driver Sample / NCR_DriverProject / Src / DriverDoDriverIO.c < prev    next >
Encoding:
Text File  |  1995-04-08  |  38.6 KB  |  1,066 lines  |  [TEXT/MPCC]

  1. /*                                    DriverDoDriverIO.c                                */
  2. /*
  3.  * DriverDoDriverIO.c
  4.  * Copyright © 1994-95 Apple Computer Inc. All rights reserved.
  5.  *    Edit History
  6.  *    1994.10.24    D3    First DDK release (System A2C1)
  7.  *    1994.12.06    A5    Adding enhancements to the driver:
  8.  *                √    Folder and file reorganization (including changes to MakeFile)
  9.  *                √    Retrieve initiator bus ID from the System Registry (NVRAM property)
  10.  *                    There appears to be a bug (either in my iteration code or in
  11.  *                    the Name Registry, so this has been disabled temporarily.
  12.  *                √    (The TestDriver application will set the property for testing)
  13.  *                √    Implement Supersede/Replace (was compiled out)
  14.  *                √    Call SynchronizeIO in NCRRunScript - this needs to be checked
  15.  *                    by engineering to make sure I did this correctly, as it can't
  16.  *                    easily be checked by minimal testing.
  17.  *                √    Bug: Expansion Manager I/O routines need the device base
  18.  *                    address. (Rewrote GetPCICardBaseAddress and fixed expansion
  19.  *                    Manager calls).
  20.  *    -- below the line -- done only if there's time --
  21.  *                √    Handle discontiguous physical memory in PrepareMemoryForIO
  22.  *                    Support disconnect/reselect and, thereby, concurrent I/O.
  23.  *                    Redo the low-level routines so they can be used in a sample SIM.
  24.  *                √    Implement driver logging using a native "Audit" package.
  25.  *                √    Retrieve the power consumption information from the registry.
  26.  *    -- Waiting for A5
  27.  *                √    Implement Secondary Interrupts
  28.  * 1994.12.12 A4    Changes for the A4 DDK Release:
  29.  *                √    MappingTable is now IOPreparationTable
  30.  * 1994.12.18 A5    DriverGestalt.h is missing from this header release. Copied an
  31.  *                    old version to the folder "::PCICIncludes Temp" - this may change.
  32.  * 1994.12.30 A5+    • NCRDriver.h (the public file) now includes some system headers
  33.  *                    so it can be used independently. No substantive changes.
  34.  *                    • NCRRunScript.c now compiles if interrupts are disabled. No
  35.  *                    substantive changes. 
  36.  *                    • Moved the actual scripts from NCRRunScript.c to a separate file.
  37.  *                    • Removed scatter-gather routines from DriverPrepMemoryUtilities.c
  38.  *                    as they haven't been tested. Revised PrepareSimpleMemoryArea to
  39.  *                    follow the logic (if any) in the the develop article.
  40.  *                    • Revised script preparation for clarity (and debugging). The
  41.  *                    script now initializes constant registers.
  42.  *                    • Select (at compilation) either Memory or I/O access; not both.
  43.  *                    • Bug: CTEST0 was being written as a long, it is a byte.
  44.  *                    • Turn off timers to prevent spurious interrupts.
  45.  *                    • Set DSA to a dummy value for Bus Reset script - it doesn't use
  46.  *                    the DSA.
  47.  *                    • Removed the non-interrupt spin-loop from the script runner.
  48.  *                    Added (temporary) Software Interrupt to see if this fixes the
  49.  *                    QueueSecondaryInterrupt problem (it didn't). Turned on the
  50.  *                    watchdog timer code as it no longer crashes.
  51.  *                    • Parameterized watchdog timer (it hangs in A5).
  52.  * 1995.01.04        • Added TEMP_TEST to strip down the algorithm. This turns off
  53.  *                    PrepareMemoryForIO (the physical address is set to the logical
  54.  *                    address) and creates a minimal (successful) script.
  55.  * 1995.01.13        • Secondary interrupts work.
  56.  *                    • Correctly return power consumption by parsing the registry.
  57.  *                    • Removed many DebugStr's and removed TEMP_TEST. 
  58.  * 1995.01.22        Upgraded to A6. Added the LogLibrary functions. Removed all
  59.  *                    SecondaryInterrupt conditional compilations. Redid the way
  60.  *                    that KillIO terminates the current request as it called a
  61.  *                    secondary interrupt handler from "interrupt level" after a
  62.  *                    timeout. Log some information about the current request.
  63.  *                    • The log shows that the NCR chip -- sometimes -- jumps into
  64.  *                    the middle of a script instruction. Can this be a bus problem?
  65.  *                    Hmm, the problem went away on its own.
  66.  * 1995.01.23        • Fixed the NVRAM bug: I was using RegPropertyName rather than
  67.  *                    RegPropertyNameBuf. The former is a pointer to a character string,
  68.  *                    while the latter is a buffer that can hold a property name.
  69.  * 1995.01.24        • Removed the NVRAM bit from the driver options Control call.
  70.  *                    Added set/get initiator id (PBControl sets it, PBStatus gets it).
  71.  *                    • Cleaned up NVRAM handling. DriverReplaceCmd now fetches the
  72.  *                    initiator ID, if it can be found.
  73.  *                    • Completely rewrote PrepareMemoryForIO handling so the driver
  74.  *                    can re-called from an IOCompletion routine. This precludes
  75.  *                    allocating memory in the driver (outside of open/close). This
  76.  *                    is a massive restructuring of the driver. The new organization
  77.  *                    is described below.
  78.  *                    • Removed the DriverOptions control command: it's served its
  79.  *                    purpose, and no longer illustrates any driver-specific functions.
  80.  *                    • Removed the script log control command. The script log is now
  81.  *                    reset on each command. Hmm, the script log is outliving its
  82.  *                    usefulness, now that the LogLibrary works. Maybe it'll be
  83.  *                    the next to go.
  84.  *                    • Removed the temporary string copy definitions.
  85.  * 1995.02.03        Fixed some bugs: my PrepareMemoryForIO code used the wrong
  86.  *                    variable in one place, leading to memory corruption. Also,
  87.  *                    the atomic operation used to recover the current parameter
  88.  *                    block from the per-request record (in CompleteThisRequest)
  89.  *                    had a re-entrancy bug.
  90.  * 1995.02.06        Synchronous I/O seems to work correctly. Asynchronous I/O
  91.  *                    hangs randomly, possibly because of bugs in the NCR-specific
  92.  *                    code. Added DeviceProbe and AAPL,addresses processing.
  93.  *                    • Removed the NCR logging -- I'm relying on the LogLibrary
  94.  *                    for ongoing status logging.
  95.  *                    • Enabled watchdog timers -- the param block changed.
  96.  * 1995.02.08        • Significant changes to support the new driver organization:
  97.  *                    DMA buffers can only be passed in PBRead or PBWrite commands,
  98.  *                    and buffers must be marked with the ioMapBuffer flag in the
  99.  *                    ioPosMode field.
  100.  *                    • Hmm, Asynch I/O now seems to work.
  101.  * 1995.02.21        Missing break at Close switch statement. Added partial
  102.  *                    I/O preparation.
  103.  * 1995.03.08        • Continue testing PrepareMemoryForIO.
  104.  *                    Single-stepping scripts hang in Bus Reset
  105.  *                    • Added DelayForHardware for 12 PCI clock tick stalls.
  106.  *                    • Removed my SwapLong: now using driver services routine.
  107.  *                    • Support DriverGestaltOn(). Replace now stores the driver
  108.  *                    refNum and deviceID.
  109.  *                    • Remove TempCheckpointIO
  110.  * 1995.03.17        • Reimplemented all Name Registry routines to make them
  111.  *                    independent of the NCR driver.
  112.  *                    • Switched to a different NCR card. This has id "pci1000,4"
  113.  *                    and a different CTEST3 value. It differs from the original
  114.  *                    card in that it is 8-bit only (no wide, no fast). It's
  115.  *                    also quite a bit cheaper.
  116.  *                    • The memory leak problem may be in some other application,
  117.  *                    It doesn't seem to appear in my latest testing.
  118.  *                    • Randomly (after a few thousand trials), the watchdog
  119.  *                    timer fires immediately, rather than after the actual
  120.  *                    time (2 seconds in the test program). In reviewing the code,
  121.  *                    there appears to be a potential race condition in the sequence:
  122.  *                    Start watchdog timer then start I/.O, if this is executed
  123.  *                    from "task" level. To prevent this, I moved all I/O start
  124.  *                    to the secondary interrupt task, where it should have been
  125.  *                    all along.
  126.  *                    • SetInterruptTimer requires an interval, rather than an extact
  127.  *                    finish time. This will be fixed in the documentation.
  128.  *                    • An "engineering build" of the ROMS may have fixed the
  129.  *                    SetInterruptTimer problem. Time will tell.
  130.  *                    • Chip initialization was changed to use a read/modify/write
  131.  *                    sequence to preserve the bits that were set by the Expansion
  132.  *                    Manager.
  133.  *                    • The A8 ROMS require that SendSoftwareInterrupt be run
  134.  *                    from the Secondary Interrupt Handler.
  135.  *                    • There is a minor bug in the SendSoftwareInterrupt sequence:
  136.  *                    CancelTimer should record the amount of time remaining so that
  137.  *                    a subsequent timer restart does not reset the watchdog to its
  138.  *                    original value.
  139.  * 1995.03.29        • Still chasing timer and interrupt problems.
  140.  *                    • Restored SetInterruptTimer's documented behavior (timer
  141.  *                    fires at an epoch, not after an interval.
  142.  *                    • Before re-calling for partial preparation, we must update
  143.  *                    the IOTable's firstPrepared.
  144.  *                    • The Secondary Interrupt handler was confusing administration
  145.  *                    status (from CheckpointIO, for example), with the ioResult value
  146.  *                    that should be passed back to me caller. Hence, "selection timeout"
  147.  *                    was returning "Check Condition" status.
  148.  *                    • Use the driver refNum (converted to an OSType) as the default
  149.  *                    log entry identifier.
  150.  * 1995.04.04        • Added a 'sysz' resource (1 Mbyte) to work around a problem
  151.  *                    when logging is enabled: if three devices are installed, only one
  152.  *                    or two actually get activated. Also, device testing seems to
  153.  *                    hang in strange ways. This was not seen with the non-logging
  154.  *                    version. The value may be incorrect. This worked fine. Switching
  155.  *                    to 256 Kbytes -- still working reasonably well.
  156.  * 1995.04.05        • Debugged memory move test. Everything looks correct, but the
  157.  *                    script doesn't work. I noticed that the actual script is not
  158.  *                    32-bit aligned. Added #pragma options align=power to the headers
  159.  *                    to force the memory move script to be 32-bit aligned. If this
  160.  *                    fails, I'll add a padding halfword. Yup, that did it. Unfortunately,
  161.  *                    this means that all programs using the NCR driver must be
  162.  *                    recompiled. One more bug required a slightly more complex
  163.  *                    control flow through the Secondary Interrupt routine, which is
  164.  *                    starting to look a bit messy. Removing (with an editor) all
  165.  *                    of the test and debug junk would probably make it look better.
  166.  *                    • Revised GetDeviceLogicalAddress to use the structure in PCI.h --
  167.  *                    no substantive changes.
  168.  *                    • Some compilers are rumored to handle functions returning
  169.  *                    structures incorrectly. Store UpTime in a volatile local variable
  170.  *                    if it is to be used in a function call.
  171.  *                    • Added a function to write a message into the registry if
  172.  *                    the initialization sequence failed. It seems that I might have
  173.  *                    had a tiny error in the revised GetDeviceLogicalAddress.
  174.  *
  175.  * Preparing Memory
  176.  *        There are three active mapping tables; one for the script, one for the
  177.  *        per-request data (including data shared with the NCR chip), and one for the
  178.  *        user's I/O request. They are allocated as follows:
  179.  *        Script:        When the driver is opened, the script is "prepared" and a
  180.  *                    physical mapping table allocated. Also, a physical mapping table
  181.  *                    will allocated for user I/O requests. This uses a maximum transfer
  182.  *                    count parameter that is currently compiled in, but could easily
  183.  *                    be stored in the Name Registry. This data is released when the
  184.  *                    driver is closed.
  185.  *        PerRequest:    One of these will be allocated when the driver is opened. A future
  186.  *                    modification would allocate some larger number to support fully-
  187.  *                    concurrent I/O requests (i.e. to support disconnect/reselect).
  188.  *                    This table is released when the driver is closed.
  189.  *        User:         The user table is built into the PerRequest record. It will be
  190.  *                    initialized and checkpointed on each I/O request. This will not
  191.  *                    allocate or release memory.
  192.  *
  193.  * Misfeatures
  194.  *        The NCR Script design does not permit concurrent I/O operations, which is
  195.  *        not sufficient for a SCSI device.
  196.  *
  197.  * Open bugs
  198.  * ••• There is a problem in my understanding of the NCR chip that prevents KillIO
  199.  *        from working well. It does work, however, but sometimes leaves the bus busy.
  200.  */
  201. /*    .___________________________________________________________________________________.
  202.       | DoDriverIO, after modification, will be useful for other drivers. It shows the    |
  203.       | overall structure of the driver "top-level," calling handler functions for each    |
  204.     | driver operation. You will have to replace much of the actual driver operation    |
  205.     | with code specific to your particular purpose, but the general structure should    |
  206.     | remain the same.                                                                    |
  207.     |                                                                                    |
  208.       | These routines, after modification, will be useful for other drivers.                |
  209.     |    DriverDoDriverIO        Driver mainline. Calls hardware specific routines        |
  210.     |                            or operation-specific functions as necessary.            |
  211.     |    NameRegistryUtilities    Store and retrieve information from the Name Registery    |
  212.     |    DriverPCIBusUtilities    Utilities to read and write data on the PCI bus. There    |
  213.     |                            are functions for the Configuration registers, and for    |
  214.     |                            both Expansion Manager and direct memory access to        |
  215.     |                            chip registers.                                            |
  216.     |     DriverDebugSupport        Some very crude routines for debugging.                    |
  217.     |    DriverGestaltHandler    Process the PBStatus driver gestalt request                |
  218.     |                                                                                    |
  219.     | These routines are specific to the NCR SCSI interface. You will be able to borrow    |
  220.     | code from them, but will probably rewrite these from scratch for your driver's    |
  221.     | specific needs.                                                                    |
  222.     |    NCRChipManager            Utilities to set values in the NCR chip. This shows how    |
  223.     |                            to use the Expansion Manager routines to read and write    |
  224.     |                            device registers.                                        |
  225.     |    NCRStartScript            Prepare to execute a SCSI bus operation.                |
  226.     |    NCRRunScript            Execute a SCSI bus operation. This file includes the    |
  227.     |                            interrupt service routine.                                |
  228.     |                                                                                    |
  229.     | There is a lot of debugging code in this driver. My programming approach is to    |
  230.     | leave debugging code in the source files, but remove it automatically (by            |
  231.     | #ifdef's) from shipping versions. This is especially important for asynchronous    |
  232.     | device drivers, as they are incompatible with interactive debugging.                |
  233.     .___________________________________________________________________________________.
  234. */
  235.  
  236.  
  237. /* DriverDoDriverIO is a device driver framework that operates using the new driver
  238.  * architecture.
  239.  *
  240.  * The following overall code-flow paths are possible:
  241.  *        Immediate Commands:
  242.  *            Process command. Return an error if the request may stall (but do
  243.  *                not execute or otherwise delay the request).
  244.  *            Return the final I/O request status to the caller.
  245.  *        Other commands:
  246.  *            Process the command.
  247.  *                If it is complete (success or failure) without any delay, call
  248.  *                    IOCommandIsComplete(...) to return a result to the caller
  249.  *                    and return noErr to the Device Manager.
  250.  *                If it requires an asynchronous operation, start the operation and
  251.  *                    return noErr to the Device Manager. When the asynchronous
  252.  *                    operation completes, it will call IOCommandIsComplete.
  253.  *
  254.  * Build instructions (MetroWerks PPC)
  255.  *        Processor
  256.  *            Readonly strings            checked
  257.  *        Linker
  258.  *            Initialization                CFMInitialize
  259.  *            Main                        DoDriverIO
  260.  *            Termination                    CFMTerminate
  261.  *        PEF
  262.  *            Export Symbols                Use .exp file to export the following globals
  263.  *                                            TheDriverDescription
  264.  *                                            DoDriverIO
  265.  *            Expand uninitialized data    checked
  266.  *        Project
  267.  *            Project Type                Shared Library
  268.  *            File Name                    NCRDriver
  269.  *            File Creator                PSSD    -- Our registered creator type
  270.  *            File Type                    shlb
  271.  */
  272.  
  273. #include "NCRDriverPrivate.h"
  274.  
  275. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  276.  * We must export a global DriverDescription record that the new Device Manager
  277.  * will use to configure and instantiate our driver.
  278.  */
  279. /*
  280.  * There is a bug in some versions of the MPW PPCC compiler that cause an error if you
  281.  * try to expand fully-bracketed structures -- this structure is constructed from
  282.  * several other structures.
  283.  */
  284. DriverDescription TheDriverDescription = {
  285.     /*
  286.      * Signature info
  287.      */
  288.     kTheDescriptionSignature,                /* OSType driverDescSignature            */
  289.     kInitialDriverDescriptor,                /* DriverDescVersion driverDescVersion    */
  290.     /*
  291.      * DriverType driverType - these are defined in NCR53C825.h
  292.      */
  293.     kPCIDeviceNamePString,                    /* Name of NCR 53C825 hardware             */
  294.     kPCIRevisionID, kVersionMinor,            /* NumVersion version                    */
  295.     kVersionStageValue, kVersionRevision,
  296.     /*
  297.      * DriverOSRuntime driverOSRuntimeInfo
  298.      */
  299.     0                                        /* RuntimeOptions driverRuntime            */
  300.     | (1 * kDriverIsLoadedUponDiscovery)    /* Loader runtime options                */
  301.     | (1 * kDriverIsOpenedUponLoad)            /* Opened when loaded                    */
  302.     | (0 * kDriverIsUnderExpertControl)        /* I/O expert handles loads/opens        */
  303.     | (0 * kDriverIsConcurrent)                /* Not concurrent yet                    */
  304.     | (0 * kDriverQueuesIOPB),                /* Not internally queued yet            */
  305.     kDriverNamePString,                        /* Str31 driverName    (OpenDriver param)    */
  306.     0, 0, 0, 0, 0, 0, 0, 0,                    /* UInt32 driverDescReserved[8]            */
  307.     /*
  308.      * DriverOSService Information. This section contains a vector count followed by
  309.      * a vector of structures, each defining a driver service.
  310.      */
  311.     1,                                        /*     ServiceCount nServices                */
  312.     /*
  313.      * DriverServiceInfo service[0]
  314.      */
  315.     kServiceCategoryNdrvDriver,                /* OSType serviceCategory                */
  316.     kNdrvTypeIsGeneric,                        /* OSType serviceType                    */
  317.     kVersionMajor, kVersionMinor,            /* NumVersion serviceVersion            */
  318.     kVersionStageValue, kVersionRevision,    /* NumVersion serviceVersion            */
  319. };
  320.  
  321. /*
  322.  * All driver-global information is in a structure defined in NCRDriverPrivate.
  323.  * Note that "modern" drivers do not have access to their dce. In native Power PC
  324.  * environments, the global world is created by the Code Fragment Manager (hmm,
  325.  * perhaps it is created by CFMInitialize).
  326.  */
  327. DriverGlobal                gDriverGlobal;
  328.  
  329. OSErr                        CFMInitialize(void);
  330. OSErr                        CFMTerminate(void);
  331.  
  332. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  333.  * CFMInitialize is called by the Code Fragment Manager. This would be a good
  334.  * place to make sure that we should load in the first place -- For example,
  335.  * if necessary hardware isn't present, or there is an operating system conflict,
  336.  * we can return an error and not take up any system memory.
  337.  */
  338. OSErr
  339. CFMInitialize(void)
  340. {
  341. #if USE_LOG_LIBRARY
  342.         LogRecordPtr logRecordPtr;
  343.  
  344.         logRecordPtr = MakeLogRecord(kPCIDeviceNameCString, 256);
  345.         WriteLogEntry(logRecordPtr, 'CFMi', LogStringFormat, "\pDriver CFMInitialize");
  346. #endif
  347.         return (noErr);
  348. }
  349.  
  350. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  351.  * CFMTerminate is called by the Code Fragment Manager when the code segment
  352.  * is about to be trashed. It could dispose of any global data that is not
  353.  * managed by DoDriverIO.
  354.  */
  355. OSErr
  356. CFMTerminate(void)
  357. {
  358. #if USE_LOG_LIBRARY
  359.         LogRecordPtr logRecordPtr;
  360.  
  361.         logRecordPtr = GetLogRecordPtr(kPCIDeviceNameCString);
  362.         WriteLogEntry(logRecordPtr, 'CFMt', LogStringFormat, "\pDriver CFMTerminate");
  363. #endif
  364.         return (noErr);
  365. }
  366.  
  367. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  368.  * DoDriverIO
  369.  *
  370.  * In the new driver environment, DoDriverIO performs all driver
  371.  * functions. It is called with the following parameters:
  372.  *    IOCommandID            A unique reference for this driver request. In
  373.  *                        the emulated environment, this will be the ParamBlkPtr
  374.  *                        passed in from the Device Manager.
  375.  *    IOCommandContents    A union structure that contains information for the
  376.  *                        specific request. For the emulated environment, this
  377.  *                        will contain the following:
  378.  *        Initialize            Driver RefNum and the name registry id for this driver.
  379.  *        Finalize            Driver RefNum and the name registry id for this driver. 
  380.  *        Others                The ParamBlkPtr
  381.  *    IOCommandCode        A switch value that specifies the required function.
  382.  *    IOCommandKind        A bit-mask indicating Synchronous, Asynchronous, and Immediate
  383.  *
  384.  * For Synchronous and Immediate commands, DoDriverIO returns the final status to
  385.  * the Device Manager. For Asynchronous commands, DoDriverIO may return kIOBusyStatus.
  386.  * If it returns busy status, the driver promises to call IOCommandIsComplete when
  387.  * the transaction has completed.
  388.  */
  389. OSErr
  390. DoDriverIO(
  391.         AddressSpaceID            addressSpaceID,
  392.         IOCommandID                ioCommandID,
  393.         IOCommandContents        ioCommandContents,
  394.         IOCommandCode            ioCommandCode,
  395.         IOCommandKind            ioCommandKind
  396. )
  397. {
  398.         OSErr                    status;
  399.  
  400.         /*
  401.          * Note: Initialize, Open, KillIO, Close, and Finalize are either synchronous
  402.          * or immediate. Read, Write, Control, and Status may be immediate,
  403.          * synchronous, or asynchronous.
  404.          */
  405.         Trace(DoDriverIO);
  406.         switch (ioCommandCode) {
  407.         case kInitializeCommand:            /* Always immediate                        */
  408.             //** SysDebugStr("\p Driver Initialize");
  409. #if USE_LOG_LIBRARY
  410.             /*
  411.              * Because we can (indeed, do) have multiple cards running from the same
  412.              * device driver source, we set the default Log identifier to a unique
  413.              * string by converting the device refNum to a right-justified OSType.
  414.              */
  415.             {
  416.                 Str15            work;
  417.                 StringPtr        workPtr;
  418.  
  419.                 work[4] = 0;
  420.                 AppendSigned(&work[4], ioCommandContents.initialInfo->refNum);
  421.                 workPtr = &work[5];
  422.                 switch (work[4]) {                            /* Kids,            */
  423.                 case 0:        work[1] = ' ';    --workPtr;        /* don't            */
  424.                 case 1:        work[2] = ' ';    --workPtr;        /* try                */
  425.                 case 2:        work[3] = ' ';    --workPtr;        /* this                */
  426.                 case 3:        work[4] = ' ';    --workPtr;        /* at                */
  427.                 default:    break;                            /* home!            */
  428.                 }
  429.                 BlockCopy(workPtr, &GLOBAL.logIdentifier, sizeof (OSType));
  430.             }
  431.             GLOBAL.logRecordPtr = MakeLogRecord(kPCIDeviceNameCString, 256);
  432.             LogString("\pDoDriverIO (Initialize)");
  433.             PreserveLogRecord(GLOBAL.logRecordPtr, FALSE);    /* Wrap-around            */
  434. #endif
  435.             status = DriverInitializeCmd(
  436.                         addressSpaceID, ioCommandContents.initialInfo);
  437.             CheckStatus(status, "\pInitialize failed");
  438.             break;
  439.         case kFinalizeCommand:                /* Always immediate                        */
  440.             //** SysDebugStr("\p Driver Finalize");
  441.             LogString("\pDoDriverIO (Finalize)");
  442.             status = DriverFinalizeCmd(ioCommandContents.finalInfo);
  443.             break;
  444.         case kSupersededCommand:
  445.             //** SysDebugStr("\p Driver Superseded");
  446.             LogString("\pDoDriverIO (Supersede)");
  447.             status = DriverSupersededCmd(ioCommandContents.supersededInfo, FALSE);
  448.             break;
  449.         case kReplaceCommand:                /* replace an old driver                */
  450.             //** SysDebugStr("\p Driver Replace");
  451.             LogString("\pDoDriverIO (Replace)");
  452.             status = DriverReplaceCmd(
  453.                         addressSpaceID, ioCommandContents.replaceInfo, FALSE);
  454.             break;
  455.         case kOpenCommand:                    /* Always immediate                        */
  456.             //** SysDebugStr("\p Driver Open");
  457.             LogString("\pDoDriverIO (Open)");
  458.             status = DriverOpenCmd(addressSpaceID, ioCommandContents.pb);
  459.             CheckStatus(status, "\pOpen failed");
  460.             break;
  461.         case kCloseCommand:                    /* Always immediate                        */
  462.             //** SysDebugStr("\p Driver Close");
  463.             LogString("\pDoDriverIO (Close)");
  464.             status = DriverCloseCmd(ioCommandContents.pb);
  465.             break;
  466.         case kControlCommand:
  467.             //** SysDebugStr("\p Driver Control");
  468.             LogDecimal(
  469.                 ((CntrlParam *) ioCommandContents.pb)->csCode, "\pDoDriverIO (Control)");
  470.             status = DriverControlCmd(
  471.                         addressSpaceID,
  472.                         ioCommandID,
  473.                         ioCommandKind,
  474.                         (CntrlParam *) ioCommandContents.pb
  475.                     );
  476.             break;
  477.         case kStatusCommand:
  478.             //** SysDebugStr("\p Driver Status");
  479.             LogDecimal(
  480.                 ((CntrlParam *) ioCommandContents.pb)->csCode, "\pDoDriverIO (Status)");
  481.             status = DriverStatusCmd(
  482.                         ioCommandID,
  483.                         ioCommandKind,
  484.                         (CntrlParam *) ioCommandContents.pb
  485.                     );
  486.             break;
  487.         case kReadCommand:
  488.             //** SysDebugStr("\p Driver Read");
  489.             status = DriverReadCmd(
  490.                         addressSpaceID,
  491.                         ioCommandID,
  492.                         ioCommandKind,
  493.                         ioCommandContents.pb
  494.                     );
  495.             break;
  496.         case kWriteCommand:
  497.             //** LogString("\p Driver Write");
  498.             status = DriverWriteCmd(
  499.                         addressSpaceID,
  500.                         ioCommandID,
  501.                         ioCommandKind,
  502.                         ioCommandContents.pb
  503.                     );
  504.             break;
  505.         case kKillIOCommand:                /* Always immediate                        */
  506.             //** SysDebugStr("\p Driver Killio");
  507.             LogString("\pDoDriverIO (KillIO)");
  508.             status = DriverKillIOCmd(ioCommandContents.pb);
  509.             break;
  510.         default:
  511.             //** SysDebugStr("\p Driver Bogus");
  512.             LogHex((UInt32) ioCommandCode, "\pUnknown DoDriverIO IOCommandCode");
  513.             status = paramErr;
  514.             break;
  515.         }
  516.         /*
  517.          * Force a valid result for immediate commands -- they must return a valid
  518.          * status to the Driver Manager: returning kIOBusyStatus would be a bug..
  519.          * Non-immediate commands return a status from the lower-level routine. If the
  520.          * status is kIOBusyStatus, we just return -- an asynchronous I/O completion
  521.          * routine will eventually complete the request. If it's some other status, the
  522.          * lower-level routine has completed a non-immediate task, so we call
  523.          * IOCommandIsComplete and return its (presumably noErr) status.
  524.          */
  525.         if ((ioCommandKind & kImmediateIOCommandKind) != 0) {
  526.             ;            /* Immediate commands return the operation status        */
  527.         }
  528.         else if (status == kIOBusyStatus) {
  529.             /*
  530.              * An asynchronous operation is in progress. The driver handler promises
  531.              * to call IOCommandIsComplete when the operation concludes.
  532.              */
  533.             status = noErr;
  534.         }
  535.         else {
  536.             /*
  537.              * Normal command that completed synchronously. Dequeue the user's
  538.              * parameter block.
  539.              */
  540.             status = IOCommandIsComplete(ioCommandID, status);
  541.         }
  542.         return (status);
  543. }
  544.  
  545.  
  546. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  547.  * DriverInitializeCmd
  548.  *
  549.  * The New Driver Manager calls this when the driver is first opened.
  550.  */
  551. OSErr
  552. DriverInitializeCmd(
  553.         AddressSpaceID            addressSpaceID,
  554.         DriverInitInfoPtr        driverInitInfoPtr
  555.     )
  556. {
  557.         OSErr                    status;
  558.         ByteCount                unusedAreaLength;
  559.         static const Nanoseconds    gNsecClockTick12 = { 0, 12 * 33 };
  560.  
  561.         Trace(DriverInitializeCmd);
  562.         GLOBAL.pageSize = GetLogicalPageSize();
  563.         GLOBAL.pageMask = GLOBAL.pageSize - 1;
  564.         GLOBAL.refNum = driverInitInfoPtr->refNum;
  565.         GLOBAL.deviceEntry = driverInitInfoPtr->deviceEntry;
  566.         /*
  567.          * Compute 12 PCI clock ticks in AbsoluteTime units. Currently, we
  568.          * know that the PCI clock cycle is 33 nsec/tick. In the future, we
  569.          * should retrieve the PCI clock speed from the Name Registry.
  570.          */
  571.         GLOBAL.clockTick12 = NanosecondsToAbsolute(gNsecClockTick12);
  572.         GLOBAL.msec250 = DurationToAbsolute(250 * durationMillisecond);
  573.         status = InstallDriverInterruptFunction(
  574.                     &GLOBAL.deviceEntry,
  575.                     PCIInterruptServiceRoutine,
  576.                     &GLOBAL.interruptSetMember,
  577.                     &GLOBAL.interruptSetRefcon,
  578.                     &GLOBAL.interruptServiceFunction,
  579.                     &GLOBAL.interruptEnableFunction,
  580.                     &GLOBAL.interruptDisableFunction
  581.                 );
  582.         CheckStatus(status, "\pInstallDriverInterruptFunction failed");
  583.         if (status == noErr) {
  584.             status = GetDeviceLogicalAddress(
  585.                         &GLOBAL.deviceEntry,
  586. #if USE_MEM_ACCESS
  587.                         kPCIMemoryBaseRegister,
  588. #else
  589.                         kPCIIOBaseRegister,
  590. #endif
  591.                         &GLOBAL.pciCardBaseAddress,
  592.                         &unusedAreaLength
  593.                     );
  594.             CheckStatus(status, "\pGetPCICardBaseAddress failed");
  595.         }
  596.         if (status == noErr)
  597.             status = NCRInitializeChip();
  598.         if (status == noErr)
  599.             status = DriverReplaceCmd(
  600.                         addressSpaceID,
  601.                         (DriverReplaceInfoPtr) driverInitInfoPtr,
  602.                         TRUE
  603.                     );
  604.         if (status != noErr && GLOBAL.interruptDisableFunction != NULL) {
  605.             (*GLOBAL.interruptDisableFunction)(
  606.                         GLOBAL.interruptSetMember,
  607.                         GLOBAL.interruptSetRefcon
  608.                     );
  609.             GLOBAL.interruptDisableFunction = NULL;
  610.         }
  611.         return (status);
  612. }
  613.  
  614. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  615.  * DriverReplaceCmd
  616.  *
  617.  * We are replacing an existing driver -- or are completing an initialization sequence.
  618.  * Retrieve any state information from the Name Registry (we have none), install
  619.  * our interrupt handlers, and activate the device.
  620.  *
  621.  * We don't use the calledFromInitialize parameter, but it's here so that a driver can
  622.  * distinguish between initialization (fetch only the NVRAM parameter) and replacement
  623.  * (fetch state information that may be left-over from the previous incantation).
  624.  */
  625. OSErr
  626. DriverReplaceCmd(
  627.         AddressSpaceID            addressSpaceID,
  628.         DriverReplaceInfoPtr    driverReplaceInfoPtr,
  629.         Boolean                    calledFromInitialize
  630.     )
  631. {
  632.         OSErr                    status;
  633.         NCRDriverInitiatorIDParam pb;
  634.  
  635.         Trace(DriverReplaceCmd);
  636.         UNUSED(addressSpaceID);
  637.         UNUSED(calledFromInitialize);
  638.         GLOBAL.refNum = driverReplaceInfoPtr->refNum;
  639.         GLOBAL.deviceEntry = driverReplaceInfoPtr->deviceEntry;
  640.         PublishDriverDebugInfo();
  641.         CLEAR(pb);
  642.         GLOBAL.initiatorID = kSCSIInitiatorID;
  643.         InitializeSCSIInitiatorID();
  644. //** For debugging, defer PatchScript until the first NCR operation so the test
  645. //** tool can dump the un-compiled script.
  646. //**    status = NCRPatchScript();
  647.         status = noErr;
  648.         if (status == noErr)
  649.             status = DriverGestaltOn(GLOBAL.refNum);
  650.         if (status == noErr)
  651.             status = PrepareMemoryForScript(addressSpaceID);
  652.         if (status == noErr)
  653.             status = CreatePerRequestRecord(addressSpaceID);
  654.         if (status == noErr) {
  655.             /*
  656.              * Initialize the hardware.
  657.              */
  658.             status = NCRResetChip(kNCRResetChipInitialize);
  659.             CheckStatus(status, "\pNCRResetChip failed");
  660.         }
  661.         if (status != noErr)
  662.             PublishInitFailureMsg(status, "\pDriverReplaceCmd failure");
  663.         return (status);
  664. }
  665.  
  666. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  667.  * DriverFinalizeCmd
  668.  *
  669.  * Process a DoDriverIO finalize command.
  670.  */
  671. OSErr
  672. DriverFinalizeCmd(
  673.         DriverFinalInfoPtr        driverFinalInfoPtr
  674.     )
  675. {
  676.         Trace(DriverFinializeCmd);
  677.         (void) DriverSupersededCmd((DriverSupersededInfoPtr) driverFinalInfoPtr, TRUE);
  678.         CLEAR(GLOBAL);
  679.         return (noErr);
  680. }
  681.  
  682. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  683.  * DriverSupersededCmd
  684.  *
  685.  * We are shutting down, or being replaced by a later driver. Wait for all I/O to
  686.  * complete and store volatile state in the Name Registry whree it will be retrieved
  687.  * by our replacement.
  688.  */
  689. OSErr
  690. DriverSupersededCmd(
  691.         DriverSupersededInfoPtr    driverSupersededInfoPtr,
  692.         Boolean                    calledFromFinalize
  693.     )
  694. {
  695.         Trace(DriverSupersededCmd);
  696.         UNUSED(driverSupersededInfoPtr);
  697.         UNUSED(calledFromFinalize);
  698.         /*
  699.          * This duplicates DriverKillIOCmd, the correct algorithm would wait for
  700.          * concurrent I/O to complete. Hmm, what about "infinite wait" I/O, such
  701.          * as would be posted by a modem server or socket listener? Note that
  702.          * this section needs to be extended to handle all pending requests.
  703.          *
  704.          * It's safe to call CompleteThisRequest, as that routine uses an atomic
  705.          * operation that allows it to be called when no request is pending without
  706.          * any possible problems. Since it's a secondary interrupt handler, we
  707.          * need to call it through the Driver Services Library.
  708.          *
  709.          * Warning: GLOBAL.perRequestDataPtr will be NULL if initialization fails
  710.          * and the Driver Manager tries to terminate us. When we permit concurrent
  711.          * requests, this will loop on all per-request records.
  712.          */
  713.         if (GLOBAL.perRequestDataPtr == NULL)
  714.             LogString("\pSupersede called before initialization complete");
  715.         else {
  716.             CancelWatchdogTimer(GLOBAL.perRequestDataPtr);
  717.             (void) NCRResetChip(kNCRStopCurrentScript);
  718.             (void) NCRSecondaryInterruptHandler(
  719.                         GLOBAL.perRequestDataPtr, (void *) abortErr);
  720.             DisposePerRequestRecord(&GLOBAL.perRequestDataPtr);
  721.         }
  722.         DisposePerRequestRecord(&GLOBAL.perRequestDataPtr);
  723.         DisposeMemoryForScript();
  724.         if (GLOBAL.interruptDisableFunction != NULL) {
  725.             (*GLOBAL.interruptDisableFunction)(
  726.                         GLOBAL.interruptSetMember,
  727.                         GLOBAL.interruptSetRefcon
  728.                     );
  729.             GLOBAL.interruptDisableFunction = NULL;
  730.         }
  731.         CLEAR(GLOBAL);
  732.         return (noErr);
  733. }
  734.  
  735. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  736.  * DriverControlCmd
  737.  *
  738.  * Process a PBControl command.
  739.  */
  740. OSErr
  741. DriverControlCmd(
  742.         AddressSpaceID            addressSpaceID,
  743.         IOCommandID                ioCommandID,
  744.         IOCommandKind            ioCommandKind,
  745.         CntrlParam                *pb
  746.     )
  747. {
  748.         OSErr                    status;
  749.         UInt8                    initiatorID;
  750.  
  751.         Trace(DriverControlCmd);
  752.         UNUSED(ioCommandKind);
  753.         switch (pb->csCode) {
  754.         case driverPowerLow:
  755.             status = NCRResetChip(kNCRResetChipPowerDown);
  756.             break;
  757.         case driverPowerHigh:
  758.             status = NCRResetChip(kNCRResetChipPowerUp);
  759.             break;
  760.         case kControlDoSCSIBusReset:
  761.             /*
  762.              * NCRPatchScript is here so that the test program can dump
  763.              * the script in its un-patched format.
  764.              */
  765.             status = NCRPatchScript();        /* TEMP    */
  766.             if (status != noErr) break;        /* TEMP */
  767.             status = NCRStartScript(
  768.                         addressSpaceID,
  769.                         ioCommandID,
  770.                         (ParmBlkPtr) pb,
  771.                         kBusResetScript
  772.                     );
  773.             break;
  774.         case kControlDoSCSIRundown:
  775.             status = NCRPatchScript();        /* TEMP */
  776.             if (status != noErr) break;        /* TEMP */
  777.             status = NCRStartScript(
  778.                         addressSpaceID,
  779.                         ioCommandID,
  780.                         (ParmBlkPtr) pb,
  781.                         kSCSIRundownScript
  782.                     );
  783.             break;
  784.         case kControlGetOrSetInitiatorID:
  785.             initiatorID = ((NCRDriverInitiatorIDParamPtr) pb)->initiatorID;
  786.             status = SetSCSIInitiatorID(initiatorID);
  787.             break;
  788.         case kControlGoodbye:                    /* Unused                            */
  789.             /*
  790.              * We should reset the NCR Chip, but we'll wait for Finalize
  791.              */
  792.             status = noErr;
  793.             break;
  794.         default:
  795.             LogDecimal(pb->csCode, "\pUnknown PBControl csCode");
  796.             status = controlErr;                /* Unknown csCode                    */
  797.             break;
  798.         }
  799.         return (status);
  800. }
  801.  
  802. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  803.  * DriverStatusCmd
  804.  *
  805.  * Process a PBStatus command. We support the driver gestalt call and our private
  806.  * debugging commands.
  807.  */
  808. OSErr
  809. DriverStatusCmd(
  810.         IOCommandID                ioCommandID,
  811.         IOCommandKind            ioCommandKind,
  812.         CntrlParam                *pb
  813.     )
  814. {
  815.         OSErr                    status;
  816.         UInt8                    initiatorID;
  817. #define PB        (*pb)
  818.  
  819.         Trace(DriverStatusCmd);
  820.         UNUSED(ioCommandID);
  821.         UNUSED(ioCommandKind);        /* Always synchronous - actually, we don't care */
  822.         switch (PB.csCode) {
  823.         case csDriverGestaltCode:
  824.             status = DriverGestaltHandler(pb);
  825.             break;
  826.         case kControlGetOrSetInitiatorID:
  827.             status = GetSCSIInitiatorID(&initiatorID);
  828.             if (status == noErr)
  829.                 ((NCRDriverInitiatorIDParamPtr) pb)->initiatorID = initiatorID;
  830.             break;
  831.         default:
  832.             LogDecimal(PB.csCode, "\pUnknown PBStatus csCode");
  833.             status = statusErr;
  834.             break;
  835.         }
  836.         return (status);
  837. #undef PB
  838. }
  839.  
  840. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  841.  * DriverKillIOCmd stops all I/O for this chip. It's a big hammer, use it wisely.
  842.  * This will need revision when we support concurrent I/O as we must stop all
  843.  * pending requests.
  844.  */
  845. OSErr
  846. DriverKillIOCmd(
  847.         ParmBlkPtr                pb
  848.     )
  849. {
  850. #define REQUEST    (GLOBAL.perRequestData)
  851.  
  852.         Trace(DriverKillIOCmd);
  853.         UNUSED(pb);
  854.         /*
  855.          * This presumes that, when NCRResetChip interrupts, it will complete the
  856.          * current request, if any.
  857.          */
  858.         (void) NCRResetChip(kNCRStopCurrentScript);
  859.         return (noErr);
  860. #undef REQUEST
  861. }
  862.  
  863. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  864.  * DriverReadCmd
  865.  *
  866.  * The caller passes the data buffer and buffer length in the IOParam record and
  867.  * a pointer to a SCSI NCRSCSIParam in the ioMisc field.
  868.  */
  869. OSErr
  870. DriverReadCmd(
  871.         AddressSpaceID            addressSpaceID,
  872.         IOCommandID                ioCommandID,
  873.         IOCommandKind            ioCommandKind,
  874.         ParmBlkPtr                pb
  875.     )
  876. {
  877.         OSErr                    status;
  878. #define PB        (pb->ioParam)
  879. #define SCSI    (*((NCRSCSIParamPtr) PB.ioMisc))
  880.  
  881.         Trace(DriverReadCmd);
  882.         UNUSED(ioCommandKind);
  883.         if (PB.ioMisc == NULL)
  884.             status = paramErr;
  885.         else if ((SCSI.driverAction & kNCRDriverOutputAllowed) != 0)
  886.             status = scsiRequestInvalid;
  887.         else {
  888.             status = NCRStartScript(
  889.                         addressSpaceID,
  890.                         ioCommandID,
  891.                         pb,
  892.                         kSCSICommandScript
  893.                     );
  894.         }
  895.         return (status);
  896. #undef PB
  897. #undef SCSI
  898. }
  899.  
  900.  
  901. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  902.  * DriverReadCmd is not supported as we need the SCSI command and the target ID.
  903.  */
  904. OSErr
  905. DriverWriteCmd(
  906.         AddressSpaceID            addressSpaceID,
  907.         IOCommandID                ioCommandID,
  908.         IOCommandKind            ioCommandKind,
  909.         ParmBlkPtr                pb
  910.     )
  911. {
  912.         OSErr                    status;
  913. #define PB        (pb->ioParam)
  914. #define SCSI    (*((NCRSCSIParamPtr) PB.ioMisc))
  915.  
  916.         Trace(DriverWriteCmd);
  917.         UNUSED(ioCommandKind);
  918.         if (PB.ioMisc == NULL)
  919.             status = paramErr;
  920.         else if ((SCSI.driverAction & kNCRDriverInputAllowed) != 0)
  921.             status = scsiRequestInvalid;
  922.         else {
  923.             status = NCRStartScript(
  924.                         addressSpaceID,
  925.                         ioCommandID,
  926.                         pb,
  927.                         kSCSICommandScript
  928.                     );
  929.         }
  930.         return (status);
  931. #undef PB
  932. #undef SCSI
  933. }
  934.  
  935. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  936.  * DriverCloseCmd does nothing..
  937.  */
  938. OSErr
  939. DriverCloseCmd(
  940.         ParmBlkPtr                pb
  941.     )
  942. {
  943.         Trace(DriverCloseCmd);
  944.         UNUSED(pb);
  945.         return (noErr);
  946. }
  947.  
  948. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  949.  * DriverOpenCmd does nothing: remember that many applications will open a device, but
  950.  * never close it..
  951.  */
  952. OSErr
  953. DriverOpenCmd(
  954.         AddressSpaceID            addressSpaceID,
  955.         ParmBlkPtr                pb
  956.     )
  957. {
  958.         Trace(DriverOpenCmd);
  959.         UNUSED(addressSpaceID);
  960.         UNUSED(pb);
  961.         return (noErr);
  962. }
  963.  
  964. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  965.  * GetSCSIInitiatorID
  966.  *
  967.  * Retrieve the initiator ID from the Name Registry. This may be called from the
  968.  * driver Status handler. It does not modify the NCR initiator ID (SetSCSIInitiatorID
  969.  * will do this).
  970.  */
  971. OSErr
  972. GetSCSIInitiatorID(
  973.         UInt8                    *initiatorID
  974.     )
  975. {
  976.         OSErr                    status;
  977.         UInt8                    driverNVRAMRecord[8];
  978.  
  979.         Trace(GetSCSIInitiatorID);
  980.         status = GetDriverNVRAMProperty(
  981.                 &GLOBAL.deviceEntry,
  982.                 kCreatorType,
  983.                 driverNVRAMRecord
  984.             );
  985.         if (status == noErr)
  986.             *initiatorID = driverNVRAMRecord[0];
  987.         return (status);
  988. }
  989.  
  990. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  991.  * SetSCSIInitiatorID
  992.  *
  993.  * Store the initiator ID in our global area. It will take effect on the next SCSI
  994.  * request: this may cause a subtle race condition if asynchronous I/O is in progress.
  995.  * This function is really here only to illustrate/test NVRAM configuration.
  996.  *
  997.  * Note: because this may create a property in the Name Registry, it must be called
  998.  * from an application "task" context.
  999.  */
  1000. OSErr
  1001. SetSCSIInitiatorID(
  1002.         UInt8                    initiatorID
  1003.     )
  1004. {
  1005.         OSErr                    status;
  1006.         UInt8                    driverNVRAMRecord[8];
  1007.  
  1008.         Trace(SetSCSIInitiatorID);
  1009.         if (initiatorID > kMaxSCSIInitiatorID)
  1010.             status = paramErr;
  1011.         else {
  1012.             /*
  1013.              * This should really wait until all I/O is complete.
  1014.              */
  1015.             GLOBAL.initiatorID = initiatorID;
  1016.             CLEAR(driverNVRAMRecord);
  1017.             driverNVRAMRecord[0] = GLOBAL.initiatorID;
  1018.             status = UpdateDriverNVRAMProperty(
  1019.                     &GLOBAL.deviceEntry,
  1020.                     kCreatorType,
  1021.                     driverNVRAMRecord
  1022.                 );
  1023.         }
  1024.         return (status);
  1025. }
  1026.  
  1027. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1028.  * InitializeSCSIInitiatorID
  1029.  *
  1030.  * Retrieve the initiator ID from our NVRAM property. Called from initialization.
  1031.  */
  1032. void
  1033. InitializeSCSIInitiatorID(void)
  1034. {
  1035.         OSErr                    status;
  1036.         UInt8                    driverNVRAMRecord[8];
  1037.  
  1038.         Trace(InitializeSCSIInitiatorID);
  1039.         CLEAR(driverNVRAMRecord);
  1040.         status = RetrieveDriverNVRAMProperty(
  1041.                     &GLOBAL.deviceEntry,
  1042.                     kCreatorType,
  1043.                     driverNVRAMRecord
  1044.                 );
  1045.         switch (status) {
  1046.         case noErr:                    /* Found in NVRAM                            */
  1047.             GLOBAL.initiatorID = driverNVRAMRecord[0];
  1048.             break;
  1049.         case nrNotFoundErr:            /* Not in NVRAM                                */
  1050.         case paramErr:                /* Deleted bogus NVRAM property                */
  1051.         default:                    /* Some other Name Registry error            */
  1052.             /*
  1053.              * Create the NVRAM property.
  1054.              */
  1055.             CLEAR(driverNVRAMRecord);
  1056.             driverNVRAMRecord[0] = GLOBAL.initiatorID;
  1057.             status = CreateDriverNVRAMProperty(
  1058.                         &GLOBAL.deviceEntry,
  1059.                         kCreatorType,
  1060.                         driverNVRAMRecord
  1061.                     );
  1062.             break;
  1063.         }
  1064.         CheckStatus(status, "\pInitializeSCSIInitiatorID");
  1065. }
  1066.